import logging
from datetime import datetime

from src.core.exceptions.subscription import (
    AddedCalendarsLimitReached,
    CalendarAlreadyAdded,
)
from src.core.models.dto import (
    CalendarDTO,
    CalendarWithTasksAndMessagesDTO,
    UserCalendarDTO,
)
from src.core.models.enums import SubscriptionType, UserCalendarStatus
from src.database.models import User, UserCalendar
from src.database.uow import SQLAlchemyUoW

logger = logging.getLogger(__name__)


class CalendarService:
    def __init__(self, uow: SQLAlchemyUoW):
        self._uow = uow

    async def get_calendar_by_id(
        self, calendar_id: int
    ) -> CalendarWithTasksAndMessagesDTO:
        """Получаем календарь по id"""

        return await self._uow.calendar_reader.get_calendar_by_id(calendar_id)

    async def get_user_calendar_by_id(
        self, calendar_id: int, subscription_id: int
    ) -> UserCalendarDTO | None:
        """Получаем календарь пользователя"""

        return await self._uow.calendar_reader.get_user_calendar_by_id(
            calendar_id, subscription_id
        )

    async def get_calendars_in_category(self, category_id: int) -> list[CalendarDTO]:
        """Получаем календари в категории"""

        return await self._uow.calendar_reader.get_calendars_in_category(category_id)

    async def get_user_calendars(self, user_tg_id: int) -> list[UserCalendarDTO]:
        """Получаем календари пользователя"""

        return await self._uow.calendar_reader.get_user_calendars(user_tg_id)

    async def get_active_users_calendars(self) -> list[UserCalendarDTO]:
        """Получаем активные календари пользователей"""

        return await self._uow.calendar_reader.get_active_users_calendars()

    async def assign_calendar_to_user(self, calendar_id: int, user_tg_id: int):
        """Добавляем календарь в подписку пользователя"""

        user: User = await self._uow.user_reader.get_user_by_tg_id(user_tg_id)
        user_subscription = (
            await self._uow.subscription_reader.get_active_user_subscription(user_tg_id)
        )
        calendars_limit = None
        if user_subscription.type == SubscriptionType.one_calendar:
            calendars_limit = 1
        elif user_subscription.type == SubscriptionType.seven_calendars:
            calendars_limit = 7
        if calendars_limit and user_subscription.calendars_count >= calendars_limit:
            raise AddedCalendarsLimitReached

        if await self._uow.calendar_reader.get_user_calendar_by_id(
            calendar_id, user_subscription.id
        ):
            raise CalendarAlreadyAdded

        user_calendar = UserCalendar(
            user_id=user.id,
            calendar_id=calendar_id,
            subscription_id=user_subscription.id,
        )
        try:
            await self._uow.calendar_repo.create_calendar(user_calendar)
        except Exception as err:
            await self._uow.rollback()
            raise err

        await self._uow.commit()

    async def update_user_get_tasks_time(
        self, user_calendar_id: int, get_tasks_time: datetime.time
    ) -> None:
        """Заменяем время отправки заданий"""

        user_calendar: UserCalendar = (
            await self._uow.calendar_repo.acquire_user_calendar_by_id(user_calendar_id)
        )
        user_calendar.get_tasks_time = get_tasks_time

        await self._uow.calendar_repo.update_calendar(user_calendar)

        await self._uow.commit()

    async def update_user_check_tasks_time(
        self, user_calendar_id: int, check_tasks_time: datetime.time
    ) -> None:
        """Заменяем время проверки заданий"""

        user_calendar: UserCalendar = (
            await self._uow.calendar_repo.acquire_user_calendar_by_id(user_calendar_id)
        )
        user_calendar.check_tasks_time = check_tasks_time

        await self._uow.calendar_repo.update_calendar(user_calendar)

        await self._uow.commit()

    async def update_calendar_tasks_sended(
        self, user_calendar_id: int, tasks_sended: int = 1
    ):
        """Обновляем число отправленных задач"""

        user_calendar: UserCalendar = (
            await self._uow.calendar_repo.acquire_user_calendar_by_id(user_calendar_id)
        )
        user_calendar.tasks_sent += tasks_sended

        try:
            await self._uow.calendar_repo.update_calendar(user_calendar)
        except Exception as err:
            await self._uow.rollback()
            raise err

        await self._uow.commit()
        logger.info(
            f"User calendar №{user_calendar_id} tasks sent was updated. New value: {user_calendar.tasks_sent}"
        )

    async def update_calendar_status(
        self, user_calendar_id: int, status: UserCalendarStatus
    ):
        """Обновляем статус календаря"""

        user_calendar: UserCalendar = (
            await self._uow.calendar_repo.acquire_user_calendar_by_id(user_calendar_id)
        )
        user_calendar.status = status

        try:
            await self._uow.calendar_repo.update_calendar(user_calendar)
        except Exception as err:
            await self._uow.rollback()
            raise err

        await self._uow.commit()
        logger.info(
            f"User calendar №{user_calendar_id} status was updated. New status: {status}"
        )

    async def update_calendar_successful_tasks(
        self, user_calendar_id: int, successful_tasks: int = 1
    ):
        """Обновляем количество успешных заданий календаря"""

        user_calendar: UserCalendar = (
            await self._uow.calendar_repo.acquire_user_calendar_by_id(user_calendar_id)
        )
        user_calendar.successful_tasks += successful_tasks

        try:
            await self._uow.calendar_repo.update_calendar(user_calendar)
        except Exception as err:
            await self._uow.rollback()
            raise err

        await self._uow.commit()
